package main

/*
#include <string.h>
*/
import "C"
import (
	"encoding/asn1"
	"fmt"
	"github.com/tjfoc/gmsm/x509"
	"goes/assets"
	"goes/gmseal"
	"strconv"
	"unsafe"
)

func main() {
}

const (
	ProductionName    = "goes"
	ProductionCompany = "ofdrw"
	ProductionVersion = "1.0.0"
	SealList          = "Seal.esl"
)

//export OES_GetProviderInfo
func OES_GetProviderInfo(puchName *C.uchar, piNameLen *C.int,
	puchCompany *C.uchar, piCompanyLen *C.int,
	puchVersion *C.uchar, piVersionLen *C.int,
	puchExtend *C.uchar, piExtendLen *C.int) C.int {

	lenFlag := false
	if puchName == nil || puchCompany == nil || puchVersion == nil {
		lenFlag = true
	}
	name := []byte(ProductionName)
	company := []byte(ProductionCompany)
	version := []byte(ProductionVersion)
	if piNameLen != nil {
		*piNameLen = C.int(len(name))
	}
	if piCompanyLen != nil {
		*piCompanyLen = C.int(len(company))
	}
	if piVersionLen != nil {
		*piVersionLen = C.int(len(version))
	}
	if piExtendLen != nil {
		*piExtendLen = 0
	}

	if lenFlag {
		return 0
	}
	if puchName != nil {
		C.memcpy(unsafe.Pointer(puchName), unsafe.Pointer(&name[0]), C.size_t(len(name)))
	}
	if puchCompany != nil {
		C.memcpy(unsafe.Pointer(puchCompany), unsafe.Pointer(&company[0]), C.size_t(len(company)))
	}
	if puchVersion != nil {
		C.memcpy(unsafe.Pointer(puchVersion), unsafe.Pointer(&version[0]), C.size_t(len(version)))
	}
	return 0
}

//export OSE_GetSealList
func OSE_GetSealList(puchSealListData *C.uchar, piSealListDataLen *C.int) C.int {
	sealList := []byte(SealList)
	size := C.int(len(sealList))
	if piSealListDataLen != nil {
		*piSealListDataLen = size
	}
	if puchSealListData != nil {
		C.memcpy(unsafe.Pointer(puchSealListData), unsafe.Pointer(&sealList[0]), C.size_t(len(sealList)))
	}

	return 0
}

//export OES_GetSeal
func OES_GetSeal(puchSealId *C.uchar, iSealIdLen C.int,
	puchSealData *C.uchar, piSealDataLen *C.int) C.int {
	if puchSealId != nil && iSealIdLen > 0 {
		fmt.Println(">> OES_GetSeal ID:", gStr(puchSealId, &iSealIdLen))
	}
	seal := assets.Seal()
	size := C.int(len(seal))
	if piSealDataLen != nil {
		*piSealDataLen = size
	}
	if puchSealData != nil {
		C.memcpy(unsafe.Pointer(puchSealData), unsafe.Pointer(&seal[0]), C.size_t(len(seal)))
	}
	return 0
}

//export OES_GetSealInfo
func OES_GetSealInfo(
	puchData *C.uchar, iDataLen C.int,
	puchSealId *C.uchar, iSealIdLen *C.int,
	puchVersion *C.uchar, iVersionLen *C.int,
	puchVenderId *C.uchar, iVenderIdLen *C.int,
	puchSealType *C.uchar, iSealTypeLen *C.int,
	puchSealName *C.uchar, iSealNameLen *C.int,
	puchCertInfo *C.uchar, iCertInfoLen *C.int,
	puchValidStart *C.uchar, iValidStartLen *C.int,
	puchValidEnd *C.uchar, iValidEndLen *C.int,
	puchSignedDate *C.uchar, iSignedDateLen *C.int,
	puchSignerName *C.uchar, iSignerNameLen *C.int,
	puchSignMethod *C.uchar, iSignMethodLen *C.int) C.int {
	if puchData == nil || iDataLen == 0 {
		return -1
	}
	raw := C.GoBytes(unsafe.Pointer(puchData), iDataLen)
	var seal gmseal.SESeal
	_, err := asn1.Unmarshal(raw, &seal)
	if err != nil {
		fmt.Printf("印章解析失败 %v\n", err)
		return -1
	}
	header := seal.ESealInfo.Header
	sealId := []byte(header.ID)
	version := []byte(strconv.Itoa(header.Version))
	venderId := []byte(header.Vid)
	property := seal.ESealInfo.Property
	sealType := []byte(strconv.Itoa(property.Type))
	sealName := []byte(property.Name)
	certInfo := property.CertList.FullBytes
	validStart := []byte(property.ValidStart.Format("20060102150405Z0700"))
	validEnd := []byte(property.ValidEnd.Format("20060102150405Z0700"))
	signedDate := []byte(property.CreateDate.Format("20060102150405Z0700"))

	signerCert, _ := x509.ParseCertificate(seal.Cert)
	if err != nil {
		fmt.Printf("签章人证书解析失败 %v\n", err)
		return -1
	}
	signerName := []byte(signerCert.Subject.String())
	signMethod := []byte(seal.SignAlgID.String())

	if iSealIdLen != nil {
		*iSealIdLen = C.int(len(sealId))
	}
	if iVersionLen != nil {
		*iVersionLen = C.int(len(version))
	}
	if iVenderIdLen != nil {
		*iVenderIdLen = C.int(len(venderId))
	}
	if iSealTypeLen != nil {
		*iSealTypeLen = C.int(len(sealType))
	}
	if iSealNameLen != nil {
		*iSealNameLen = C.int(len(sealName))
	}
	if iCertInfoLen != nil {
		*iCertInfoLen = C.int(len(certInfo))
	}
	if iValidStartLen != nil {
		*iValidStartLen = C.int(len(validStart))
	}
	if iValidEndLen != nil {
		*iValidEndLen = C.int(len(validEnd))
	}
	if iSignedDateLen != nil {
		*iSignedDateLen = C.int(len(signedDate))
	}
	if iSignerNameLen != nil {
		*iSignerNameLen = C.int(len(signerName))
	}
	if iSignMethodLen != nil {
		*iSignMethodLen = C.int(len(signMethod))
	}

	if puchSealId != nil {
		C.memcpy(unsafe.Pointer(puchSealId), unsafe.Pointer(&sealId[0]), C.size_t(iSealIdLen))
	}
	if puchVersion != nil {
		C.memcpy(unsafe.Pointer(puchVersion), unsafe.Pointer(&version[0]), C.size_t(len(version)))
	}
	if puchVenderId != nil {
		C.memcpy(unsafe.Pointer(puchVenderId), unsafe.Pointer(&venderId[0]), C.size_t(len(venderId)))
	}
	if puchSealType != nil {
		C.memcpy(unsafe.Pointer(puchSealType), unsafe.Pointer(&sealType[0]), C.size_t(len(sealType)))
	}
	if puchSealName != nil {
		C.memcpy(unsafe.Pointer(puchSealName), unsafe.Pointer(&sealName[0]), C.size_t(len(sealName)))
	}
	if puchCertInfo != nil {
		C.memcpy(unsafe.Pointer(puchCertInfo), unsafe.Pointer(&certInfo[0]), C.size_t(len(certInfo)))
	}
	if puchValidStart != nil {
		C.memcpy(unsafe.Pointer(puchValidStart), unsafe.Pointer(&validStart[0]), C.size_t(len(validStart)))
	}
	if puchValidEnd != nil {
		C.memcpy(unsafe.Pointer(puchValidEnd), unsafe.Pointer(&validEnd[0]), C.size_t(len(validEnd)))
	}
	if puchSignedDate != nil {
		C.memcpy(unsafe.Pointer(puchSignedDate), unsafe.Pointer(&signedDate[0]), C.size_t(len(signedDate)))
	}
	if puchSignerName != nil {
		C.memcpy(unsafe.Pointer(puchSignerName), unsafe.Pointer(&signerName[0]), C.size_t(len(signerName)))
	}
	if puchSignMethod != nil {
		C.memcpy(unsafe.Pointer(puchSignMethod), unsafe.Pointer(&signMethod[0]), C.size_t(len(signMethod)))
	}
	return 0
}

// gStr 转换C的字符串为go的字符串（UTF-8）
func gStr(src *C.uchar, size *C.int) string {
	raw := C.GoBytes(unsafe.Pointer(src), *size)
	return string(raw)
}
